﻿using Common;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ImageUploader
{
    [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
    struct SendFileMessage
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
        public char[] fileName;
        //传递的包类型：1 代表发送要创建的文件，2. 代表为第一条数据 3. 为中间传输数据，并非为最后一个，4. 代表文件最后一条数据 5.第一条也是最后一条文件数据
        public char typeMessage;
        //有效数据长度
        public int effDataLength;
        //有效数据
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)]
        public byte[] effData;
    }
    class SendFileAsyncSocket
    {
        public static ManualResetEvent allDone = new ManualResetEvent(false);
        public static Socket client;
        
        public static void StartAsyncSocket(string filePath, string fileServerName)
        {
            PublicMethod pm = new PublicMethod();    
            string ip = pm.GetLocalIP();            
            IPAddress ipAddress = IPAddress.Parse(ip);
            IPEndPoint ipPoint = new IPEndPoint(ipAddress, 9999);
            client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            client.BeginConnect(ipPoint, new AsyncCallback(ConnectCallBack), client);
            allDone.WaitOne();
            while(true)
            {
                allDone.Reset();
                //发送数据                
                SendFile(client, filePath, fileServerName);
                allDone.WaitOne();
            }
        }
        public static void ConnectCallBack(IAsyncResult args)
        {            
            Socket client = (Socket)args.AsyncState;
            client.EndConnect(args);
            string msg = string.Format("Socket connected to {0}", client.RemoteEndPoint.ToString());
            //MessageInfo.type = "connect";
            //MessageInfo.msg.Add(MessageInfo.type,msg);
            allDone.Set();
        }

        public static void Send(Socket handler, byte[] byteData)
        {
            //byte[] byteData = Encoding.Unicode.GetBytes(data);
            handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallBack), handler);
        }

        private static void SendCallBack(IAsyncResult ar)
        {
            try
            {
                Socket handler = (Socket)ar.AsyncState;
                int bytesSent = handler.EndSend(ar);
                string msg = string.Format("Sent {0} bytes to server.", bytesSent);
                //MessageInfo.type = "send";
                //MessageInfo.msg.Add(MessageInfo.type, msg);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
            }
        }

        public static void SendFile(Socket client, String filePath, String serverFileName)
        {
            byte[] sendByteMessage = new byte[1037];
            FileInfo fileInfo = new FileInfo(filePath);
            int fileSize = (int)(fileInfo.Length);
            FileStream afile = new FileStream(filePath, FileMode.Open);
            SendFileMessage sfm = new SendFileMessage();
            byte[] sendDataByte = new byte[1037];
            byte[] dataByte = new byte[1024];
            int i = (int)fileSize / 1024;
            int yu = (int)fileSize % 1024;

            //< = 1024 byte，则一次性把文件发送到服务器端
            //>1024 byte的 时候，余数为0和不为0的情况，如果余数为0
            if (fileSize <= 1024)
            {
                //在此处写入到2.jpg
                afile.Seek(0, SeekOrigin.Begin);
                afile.Read(dataByte, 0, fileSize);
                sfm.effData = dataByte;
                sfm.effDataLength = fileSize;

                sfm.fileName = (serverFileName.ToCharArray());
                sfm.typeMessage = '5';
                sendDataByte = StructToBytes(sfm, 1037);
                Send(client, sendDataByte);
                afile.Close();
            }
            else
            {
                if (yu != 0)
                {
                    //余数不为0，则把其中的数据放入其中
                    for (int j = 0; j < i; j++)
                    {
                        //重新为sendByteMessage赋值。文件数据大小必须要符合要求。不然会报错。使用光照引擎来进行

                        sfm.fileName = serverFileName.ToCharArray();
                        if (j == 0)
                        {
                            sfm.typeMessage = '2';
                            sfm.fileName = serverFileName.ToCharArray();
                            sfm.effDataLength = 1024;
                        }
                        else
                            sfm.typeMessage = '3';
                        afile.Seek(j * 1024, SeekOrigin.Begin);
                        afile.Read(dataByte, 0, 1024);
                        sfm.effData = dataByte;
                        sendByteMessage = StructToBytes(sfm, 1037);
                        Send(client, sendByteMessage);
                        //全部数据发送。一定是要再接收数据.判断其中的数据，放入到里面中
                    }
                    int seekNum = i * 1024;
                    long operNum = (long)seekNum;
                    afile.Seek(operNum, SeekOrigin.Begin);
                    afile.Read(dataByte, 0, yu);
                    //在此处重新组合sfm，然后发送次文件到sfm
                    sfm.typeMessage = '4';
                    //在此处要把sfm转变为struct类型
                    sendByteMessage = StructToBytes(sfm, 1037);
                    Send(client, sendByteMessage);
                    afile.Close();
                }
                else
                {
                    for (int j = 0; j < i; j++)
                    {
                        afile.Seek(j * 1024, SeekOrigin.Begin);
                        afile.Read(dataByte, 0, 1024);
                    }
                    afile.Close();
                }
            }
        }

        private static void AsynchronousFileSendCallback(IAsyncResult ar)
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndSendFile(ar);
        }

        public static byte[] StructToBytes(object structObj, int size)
        {
            int len = Marshal.SizeOf(structObj);
            byte[] bytes = new byte[size];
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将结构体拷到分配好的内存空间
            Marshal.StructureToPtr(structObj, structPtr, false);
            //从内存空间拷贝到byte数组
            Marshal.Copy(structPtr, bytes, 0, size);
            //释放内存空间，基于8bit
            Marshal.FreeHGlobal(structPtr);
            return bytes;
        }
        public static object ByteToStruct(byte[] bytes, Type type)
        {
            int size = Marshal.SizeOf(type);
            if (size > bytes.Length)
            {
                return null;
            }
            //分配结构体
            IntPtr structPtr = Marshal.AllocHGlobal(size);
            //将byte数组拷贝到分配好的内存空间
            Marshal.Copy(bytes, 0, structPtr, size);
            //将内存空间转换为目标结构体
            object obj = Marshal.PtrToStructure(structPtr, type);
            //释放内存空间 定向光源和点光源
            Marshal.FreeHGlobal(structPtr);
            return obj;
        }

    }
}
